package com.itheima.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttribute;
import org.springframework.web.servlet.ModelAndView;

import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import domain.Book;
import domain.User;

@Controller
//@RequestMapping("/user")
public class UserController {
    //方法传递普通类型参数，数量任意，类型必须匹配
    //http://localhost/requestParam1?name=itheima
    //http://localhost/requestParam1?name=itheima&age=14
    @RequestMapping("/requestParam1")
    public String requestParam1(String name, Integer age) {
        System.out.println(name + "," + age);
        return "page.jsp";
    }

    //方法传递普通类型参数，使用@RequestParam参数匹配URL传参中的参数名称与方法形参名称
    //http://localhost/requestParam2?userName=Jock
    @RequestMapping("/requestParam2")
    public String requestParam2(@RequestParam(value = "userName", required = true) String name) {
        System.out.println(name);
        return "page.jsp";
    }

    //方法传递POJO类型参数，URL地址中的参数作为POJO的属性直接传入对象
    //http://localhost/requestParam3?name=Jock&age=39
    @RequestMapping("/requestParam3")
    public String requestParam3(User user) {
        System.out.println(user);
        return "page.jsp";
    }

    //当方法参数中具有POJO类型参数与普通类型参数，URL地址传入的参数不仅给POJO对象属性赋值，也给方法的普通类型参数赋值
    //http://localhost/requestParam4?name=Jock&age=39
    @RequestMapping("/requestParam4")
    public String requestParam4(User user, Integer age) {
        System.out.println("user=" + user + ",age=" + age);
        return "page.jsp";
    }

    //使用对象属性名.属性名的对象层次结构可以为POJO中的POJO类型参数属性赋值
    //http://localhost/requestParam5?address.city=beijing
    @RequestMapping("/requestParam5")
    public String requestParam5(User user) {
        System.out.println(user);
        return "page.jsp";
    }

    //通过URL地址中同名参数，可以为POJO中的集合属性进行赋值，集合属性要求保存简单数据
    //http://localhost/requestParam6?nick=Jock1&nick=Jockme&nick=zahc
    @RequestMapping("/requestParam6")
    public String requestParam6(User user) {
        System.out.println(user);
        return "page.jsp";
    }

    //POJO中List对象保存POJO的对象属性赋值，使用[数字]的格式指定为集合中第几个对象的属性赋值
    //http://localhost/requestParam7?addresses[0].city=beijing&addresses[1].province=hebei
    @RequestMapping("/requestParam7")
    public String requestParam7(User user) {
        System.out.println(user.getAddresses());
        return "page.jsp";
    }

    //POJO中Map对象保存POJO的对象属性赋值，使用[key]的格式指定为Map中的对象属性赋值
    //http://localhost/requestParam8?addressMap['job'].city=beijing&addressMap['home'].province=henan
    @RequestMapping("/requestParam8")
    public String requestParam8(User user) {
        System.out.println(user.getAddressMap());
        return "page.jsp";
    }

    //方法传递普通类型的数组参数，URL地址中使用同名变量为数组赋值
    //http://localhost/requestParam9?nick=Jockme&nick=zahc
    @RequestMapping("/requestParam9")
    public String requestParam9(String[] nick) {
        System.out.println(nick[0] + "," + nick[1]);
        return "page.jsp";
    }
    //    requestParam10?user[0].name=我去&user[0].age=12
    //方法传递保存普通类型的List集合时，无法直接为其赋值，需要使用@RequestParam参数对参数名称进行转换
    //http://localhost/requestParam10?nick=Jockme&nick=zahc
    @RequestMapping("/requestParam10")
    public String requestParam10(@RequestParam("nick") List<String> nick) {
        System.out.println(nick);
        for (int i = 0; i < nick.size(); i++) {


        }
        return "page.jsp";
    }

    //数据类型转换，使用自定义格式化器或@DateTimeFormat注解设定日期格式
    //两种方式都依赖springmvc的注解启动才能运行
    //http://localhost/requestParam11?date=1999-09-09
    @RequestMapping("/requestParam11")
    public String requestParam11(@DateTimeFormat(pattern = "yyyy-MM-dd") Date date) {
        System.out.println(date);
        return "page.jsp";
    }

    //数据类型转换，使用自定义类型转换器，需要配置后方可使用
    //http://localhost/requestParam12?date=1999-09-09
    @RequestMapping("/requestParam12")
    public String requestParam12(Date date) {
        System.out.println(date);
        return "page.jsp";
    }

    // 5.1 页面跳转 -----------------------------------------------
    // 转发（默认）
    // http://localhost/showPage1
    @RequestMapping("/showPage1")
    public String showPage1() {
        System.out.println("showPage1 is running ...");
        return "forward:page.jsp";
    }

    // 重定向
    // http://localhost/showPage2
    @RequestMapping("/showPage2")
    public String showPage2() {
        System.out.println("showPage2 is running ...");
        return "redirect:page.jsp";
    }


    // 5.3 带数据页面跳转 ----------------------------
    // 方式一：使用HttpServletRequest类型形参进行数据传递
    @RequestMapping("/showPageAndData1")
    public String showPageAndData1(HttpServletRequest request) {
        request.setAttribute("name", "itheima");
        return "page";
    }


    // 方式二：使用Model类型形参进行数据传递
    @RequestMapping("/showPageAndData2")
    public String showPageAndData2(Model model) {
        model.addAttribute("name", "itheima");
        Book book = new Book();
        book.setName("SpringMVC入门实战");
        book.setPrice(66.6d);
        model.addAttribute("book", book);
        return "page";
    }


    // 方式三：使用ModelAndView类型形参进行数据传递，将该对象作为返回值传递给调用者
    //使用ModelAndView形参传递参数，该对象还封装了页面信息
    @RequestMapping("/showPageAndData3")
    public ModelAndView showPageAndData3(ModelAndView modelAndView) {
        //ModelAndView mav = new ModelAndView();    替换形参中的参数
        Book book = new Book();
        book.setName("SpringMVC入门案例");
        book.setPrice(66.66d);
        //添加数据的方式，key对value
        modelAndView.addObject("book", book);
        //添加数据的方式，key对value
        modelAndView.addObject("name", "Jockme");
        //设置页面的方式，该方法最后一次执行的结果生效
        modelAndView.setViewName("page");
        //返回值设定成ModelAndView对象
        return modelAndView;
    }


    // 5.4 返回json数据 --------------------------------------
    // 方式一：基于response返回数据的简化格式，返回JSON数据
    // 使用jackson进行json数据格式转化
    @RequestMapping("/showData3")
    @ResponseBody
    public String showData3() throws JsonProcessingException {
        Book book = new Book();
        book.setName("SpringMVC入门案例");
        book.setPrice(66.66d);

        ObjectMapper om = new ObjectMapper();
        return om.writeValueAsString(book);
    }

    // 方式二：使用SpringMVC提供的消息类型转换器将对象与集合数据转换为JSON数据
    //使用SpringMVC注解驱动，对标注@ResponseBody注解的控制器方法进行结果转换，由于返回值为引用类型，自动调用jackson提供的类型转换器进行格式转换
    @RequestMapping("/showData4")
    @ResponseBody
    public Book showData4() {
        Book book = new Book();
        book.setName("SpringMVC入门案例");
        book.setPrice(66.66d);
        return book;
    }


    // 6 Servlet相关接口替换方案  --------------------------
    @RequestMapping("/servletApi")
    public String servletApi(HttpServletRequest request,
                             HttpServletResponse response, HttpSession session) {
        System.out.println(request);
        System.out.println(response);
        System.out.println(session);
        request.setAttribute("name", "session");
        session.setAttribute("name", "itheima");
        System.out.println(request.getAttribute("name"));
        return "page.jsp";
    }

    // Head数据获取
    @RequestMapping("/headApi")
    public String headApi(@RequestHeader("Accept-Language") String head) {
        System.out.println(head);
        return "page.jsp";
    }

    // Cookie数据获取
    @RequestMapping("/cookieApi")
    public String cookieApi(@CookieValue("JSESSIONID") String jsessionid) {
        System.out.println(jsessionid);
        return "page.jsp";
    }

    // Session数据获取
    @RequestMapping("/sessionApi")
    public String sessionApi(@SessionAttribute("name") String name) {
        System.out.println(name);
        return "page.jsp";
    }


}
